home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Workbench Add-On
/
Workbench Add-On - Volume 1.iso
/
Dev
/
TileForth
/
tst
/
minimal.f83
< prev
next >
Wrap
Text File
|
1995-08-25
|
10KB
|
389 lines
\
\ A MINIMAL FORTH MACHINE SIMULATOR AND META-COMPILER
\
\ Copyright (C) 1989-1990 by Mikael R.K. Patel
\
\ Computer Aided Design Laboratory (CADLAB)
\ Department of Computer and Information Science
\ Linkoping University
\ S-581 83 LINKOPING
\ SWEDEN
\
\ Email: mip@ida.liu.se
\
\ Started on: 1 August 1989
\
\ Last updated on: 23 August 1990
\
\ Dependencies:
\ (forth) forth
\
\ Description:
\ This library illustrates how a virtual forth machine and most of
\ the language can be realized with only nine primitive instructions.
\ A simulator for the minimal forth virtual machine is defined
\ together with a meta-compiler and implementations of a large
\ section of the forth language.
\
\ Copying:
\ This program is free software; you can redistribute it and\or modify
\ it under the terms of the GNU General Public License as published by
\ the Free Software Foundation; either version 1, or (at your option)
\ any later version.
\
\ This program is distributed in the hope that it will be useful,
\ but WITHOUT ANY WARRANTY; without even the implied warranty of
\ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
\ GNU General Public License for more details.
\
\ You should have received a copy of the GNU General Public License
\ along with this program; see the file COPYING. If not, write to
\ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.
.( Loading Minimal Forth Machine definitions...) cr
vocabulary minimal ( -- )
minimal definitions
forth
\ Hardware Devices: Registers and Stacks
: register ( -- ) create 0 , does> @ ;
: -> ( x -- ) ' >body [compile] literal compile ! ; immediate compilation
: stack ( n -- ) create here swap 2+ cells allot here over cell+ ! here swap ! ;
: push ( x s -- ) cell negate over +! @ ! ;
: pop ( s -- x) dup @ @ cell rot +! ;
: empty ( s -- ) dup cell+ @ swap ! ;
: ?empty ( s -- bool) 2@ = ;
: .stack ( s -- ) dup cell + @ swap @ ?do i @ . cell +loop ;
\ Forth Machine Registers
register tos ( -- x | Top of stack register)
register ir ( -- x | Instruction register)
register ip ( -- x | Instruction pointer)
64 stack rp ( -- s | Return address stack)
64 stack sp ( -- s | Parameter stack)
\ Dump machine state
: .registers ( -- )
." ir: " ir .name space ( Dump name of current instruction)
." ip: " ip cell - . ( Dump instruction pointer)
." rp: " rp .stack ( Dump return stack)
." tos: " tos . ( Dump top of stack register)
." sp: " sp .stack cr ( Dump parameter stack)
;
\ Forth Machine Instructions
: instruction ( n -- ) create ;
: decode ( -- ) minimal [compile] ['] forth ; immediate compilation
instruction 1+
instruction 0=
instruction NAND
instruction >R
instruction R>
instruction !
instruction @
instruction EXIT
instruction DUMP
: CALL ( -- ) ip rp push ir >body -> ip ;
\ The Minimal Forth Machine and additional state variables
variable trace ( -- addr | Trace function pointer)
variable cycles ( -- addr | Instruction cycle counter)
variable restart ( -- addr | Restart instruction pointer)
: reset-processor ( -- )
0 cycles ! ( Initiate cycle counter)
restart -> ip ( And instruction pointer)
0 -> tos ( Clear top of stack)
sp empty ( And empty parameter stack)
rp empty ( And return stack)
;
: fetch-instruction ( -- instruction)
1 cycles +! ( Increment cycle counter)
ip @ dup -> ir ( Fetch next instruction)
ip cell+ -> ip ( And increment instruction pointer)
;
: processor ( -- )
reset-processor
begin
fetch-instruction
trace @ ?dup if execute then
case
decode 1+ of tos 1+ -> tos endof
decode 0= of tos 0= -> tos endof
decode NAND of sp pop tos and not -> tos endof
decode >R of tos rp push sp pop -> tos endof
decode R> of tos sp push rp pop -> tos endof
decode ! of sp pop tos ! sp pop -> tos endof
decode @ of tos @ -> tos endof
decode EXIT of rp pop -> ip endof
decode DUMP of .registers endof
CALL
endcase
rp ?empty
until
;
: run ( -- ) ' restart ! processor ." cycles: " cycles @ . .registers ;
: trace-instructions ( -- ) ['] .registers trace ! ;
\ A simple meta-compiler for the Minimal Forth Machine
minimal
: CREATE ( -- ) create ;
: COMPILE ( -- ) compile compile ; immediate
: DEFINE ( -- ) CREATE ] ;
: END ( -- ) COMPILE EXIT [compile] [ ; immediate
: BLOCK ( n -- ) cells allot ;
: DATA ( -- ) , ;
\ Variable management
DEFINE [VARIABLE] ( -- addr) R> END
: VARIABLE ( -- addr) CREATE COMPILE [VARIABLE] 1 BLOCK ;
\ Constant management
DEFINE [CONSTANT] ( -- n) R> @ END
: CONSTANT ( n -- ) CREATE COMPILE [CONSTANT] DATA ;
\ Basic stack manipulation functions
VARIABLE TEMP ( -- addr)
DEFINE DROP ( x -- ) TEMP ! END
DEFINE DUP ( x -- x x) TEMP ! TEMP @ TEMP @ END
DEFINE SWAP ( x y -- y x) TEMP ! >R TEMP @ R> END
DEFINE ROT ( x y z -- y z x) >R SWAP R> SWAP END
DEFINE OVER ( x y -- x y x) >R DUP R> SWAP END
DEFINE R@ ( -- x) R> R> DUP >R SWAP >R END
\ Basic logical functions
-1 CONSTANT TRUE ( -- true)
0 CONSTANT FALSE ( -- false)
DEFINE BOOLEAN ( x -- bool) 0= 0= END
DEFINE NOT ( x y -- z) DUP NAND END
DEFINE AND ( x y -- z) NAND NOT END
DEFINE OR ( x y -- z) NOT SWAP NOT NAND END
DEFINE XOR ( x y -- y) OVER OVER NOT NAND >R SWAP NOT NAND R> NAND END
\ Primitive arithmetic constants and functions
-2147483648 CONSTANT MIN-INT ( -- int)
-2 CONSTANT -2 ( -- int)
-1 CONSTANT -1 ( -- int)
0 CONSTANT 0 ( -- int)
1 CONSTANT 1 ( -- int)
2 CONSTANT 2 ( -- int)
2147483647 CONSTANT MAX-INT ( -- int)
DEFINE 1- ( x -- y) NOT 1+ NOT END
DEFINE 2+ ( x -- y) 1+ 1+ END
DEFINE 2- ( x -- y) NOT 2+ NOT END
\ Additional relational functions
DEFINE 0< ( x -- bool) MIN-INT AND BOOLEAN END
DEFINE 0> ( x -- bool) DUP 0= SWAP 0< OR NOT BOOLEAN END
\ Cell sizes and cell increment function
4 CONSTANT CELL ( -- num)
DEFINE CELL+ ( x -- y) 1+ 1+ 1+ 1+ END
\ Branch functions
DEFINE (BRANCH) ( -- ) R> @ >R END
DEFINE (?BRANCH) ( bool -- ) 0= DUP R@ @ AND SWAP NOT R> CELL+ AND OR >R END
\ Compiler functions
: >MARK ( -- addr) here cell allot ;
: >RESOLVE ( addr -- ) here swap (forth) ! ;
: <MARK ( -- addr) here ;
: <RESOLVE ( -- addr) , ;
: IF ( bool -- ) COMPILE (?BRANCH) >MARK ; immediate
: ELSE ( -- ) COMPILE (BRANCH) >MARK swap >RESOLVE ; immediate
: THEN ( -- ) >RESOLVE ; immediate
: BEGIN ( -- ) <MARK ; immediate
: WHILE ( bool -- ) COMPILE (?BRANCH) >MARK ; immediate
: REPEAT ( -- ) COMPILE (BRANCH) swap <RESOLVE >RESOLVE ; immediate
: UNTIL ( bool -- ) COMPILE (?BRANCH) <RESOLVE ; immediate
: AGAIN ( -- ) COMPILE (BRANCH) <RESOLVE ; immediate
\ Additional stack functions
DEFINE ?DUP ( n -- [n n] or [0]) DUP IF DUP THEN END
DEFINE TUCK ( x y -- y x y) SWAP OVER END
DEFINE NIP ( x y -- y) SWAP DROP END
DEFINE 2DUP ( x y -- x y x y) OVER OVER END
DEFINE 2DROP ( x y -- ) DROP DROP END
\ Arithmetical functions
DEFINE NEGATE ( x -- y) NOT 1+ END
DEFINE ABS ( x -- y) DUP 0< IF NEGATE THEN END
DEFINE + ( x y -- z)
DUP 0<
IF BEGIN DUP WHILE 1+ SWAP 1- SWAP REPEAT
ELSE BEGIN DUP WHILE 1- SWAP 1+ SWAP REPEAT THEN
DROP
END
DEFINE - ( x y -- z) NEGATE + END
DEFINE U< ( x y -- bool)
BEGIN
DUP IF 1- ELSE 2DROP FALSE EXIT THEN
SWAP
DUP IF 1- ELSE 2DROP TRUE EXIT THEN
SWAP
AGAIN
END
DEFINE U* ( x y -- z)
>R 0 SWAP
BEGIN DUP WHILE 1- SWAP R@ + SWAP REPEAT
R> 2DROP
END
DEFINE U/MOD ( x y -- q r)
>R 0 SWAP
BEGIN DUP R@ - DUP 0< NOT WHILE SWAP DROP SWAP 1+ SWAP REPEAT
R> 2DROP
END
DEFINE * ( x y -- z)
2DUP XOR 0< >R
ABS SWAP ABS SWAP U*
R> IF NEGATE THEN
END
DEFINE /MOD ( x y -- q r)
2DUP XOR 0< >R OVER 0< >R
ABS SWAP ABS SWAP U/MOD
R> IF NEGATE THEN
R> IF SWAP NEGATE SWAP THEN
END
DEFINE / ( x y -- q) /MOD DROP END
DEFINE MOD ( x y -- r) /MOD NIP END
DEFINE = ( x y -- bool) XOR BOOLEAN NOT END
DEFINE < ( x y -- bool) - 0< END
DEFINE > ( x y -- bool) - 0> END
DEFINE MIN ( x y -- z) 2DUP > IF SWAP THEN DROP END
DEFINE MAX ( x y -- z) 2DUP < IF SWAP THEN DROP END
\ Number literals in meta-code
DEFINE (LITERAL) ( -- ) R> DUP @ SWAP CELL+ >R END
: LITERAL ( x -- ) COMPILE (LITERAL) , ; immediate
\ And some test code just to show that it actually works
DEFINE LOGIC-TEST ( -- )
[ 5 ] LITERAL NOT
[ 5 ] LITERAL [ 3 ] LITERAL AND
[ 5 ] LITERAL [ 3 ] LITERAL OR
[ 5 ] LITERAL [ 3 ] LITERAL XOR
[ 5 ] LITERAL 0=
[ 5 ] LITERAL 0<
[ 5 ] LITERAL 0>
[ 5 ] LITERAL [ 3 ] LITERAL =
[ 5 ] LITERAL [ 3 ] LITERAL <
[ 5 ] LITERAL [ 3 ] LITERAL >
[ 5 ] LITERAL [ 5 ] LITERAL =
[ 3 ] LITERAL [ 5 ] LITERAL <
[ 3 ] LITERAL [ 5 ] LITERAL >
END
run LOGIC-TEST
DEFINE ARITHMETIC-TEST ( -- )
[ 5 ] LITERAL NEGATE
[ 5 ] LITERAL ABS
[ -5 ] LITERAL ABS
[ 5 ] LITERAL [ 3 ] LITERAL MAX
[ 5 ] LITERAL [ 3 ] LITERAL MIN
[ 5 ] LITERAL [ 3 ] LITERAL +
[ 5 ] LITERAL [ 3 ] LITERAL -
[ 5 ] LITERAL [ 3 ] LITERAL *
[ 5 ] LITERAL [ -3 ] LITERAL *
[ -5 ] LITERAL [ 3 ] LITERAL *
[ -5 ] LITERAL [ -3 ] LITERAL *
[ 5 ] LITERAL [ 3 ] LITERAL /MOD
[ 5 ] LITERAL [ -3 ] LITERAL /MOD
[ -5 ] LITERAL [ 3 ] LITERAL /MOD
[ -5 ] LITERAL [ -3 ] LITERAL /MOD
END
run ARITHMETIC-TEST
DEFINE FIB ( n -- m)
DUP 1- 0= OVER 0= OR NOT
IF DUP 1- FIB SWAP 2- FIB + THEN
END
DEFINE FIB-TEST ( -- )
[ 8 ] LITERAL FIB
END
run FIB-TEST
DEFINE FAC ( n -- n!)
DUP IF DUP 1- FAC * ELSE DROP 1 THEN
END
DEFINE FAC-TEST ( -- )
[ 5 ] LITERAL FAC
END
run FAC-TEST
forth only